package com.freewater.springboot.demo.testexecutionevents;

import lombok.extern.slf4j.Slf4j;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.event.TestContextEvent;
import org.springframework.test.context.event.annotation.*;

// The EventPublishingTestExecutionListener is registered by default; however, it only publishes
// events if the ApplicationContext has already been loaded. This prevents the ApplicationContext
// from being loaded unnecessarily or too early.
//
// Consequently, a BeforeTestClassEvent will not be published until after the ApplicationContext
// has been loaded by another TestExecutionListener. For example, with the default set of
// TestExecutionListener implementations registered, a BeforeTestClassEvent will not be published
// for the first test class that uses a particular test ApplicationContext, but a BeforeTestClassEvent
// will be published for any subsequent test class in the same test suite that uses the same test
// ApplicationContext since the context will already have been loaded when subsequent test classes
// run (as long as the context has not been removed from the ContextCache via @DirtiesContext or
// the max-size eviction policy).
//
// If you wish to ensure that a BeforeTestClassEvent is always published for every test class, you
// need to register a TestExecutionListener that loads the ApplicationContext in the beforeTestClass
// callback, and that TestExecutionListener must be registered before the EventPublishingTestExecutionListener.
//
// Similarly, if @DirtiesContext is used to remove the ApplicationContext from the context cache after
// the last test method in a given test class, the AfterTestClassEvent will not be published for that test class.
@Slf4j
public class MyCustomerTestExecutionListener {

    // 在EventPublishingTestExecutionListener之前注册了AggressiveLoadApplicationContext，
    // 此监听才会被执行
    @BeforeTestClass
    public void beforeTestClass(TestContextEvent event) {
        TestContext textContext = unwrapTextContext(event);
        log.info("before test class, textContext: {}", textContext);
    }

    @PrepareTestInstance
    public void prepareTestInstance(TestContextEvent event) {
        TestContext textContext = unwrapTextContext(event);
        log.info("prepare test instance, textContext: {}", textContext);
    }

    @BeforeTestMethod
    public void beforeTestMethod(TestContextEvent event) {
        TestContext textContext = unwrapTextContext(event);
        log.info("before test method, textContext: {}", textContext);
    }

    @BeforeTestExecution
    public void beforeTestExecution(TestContextEvent event) {
        TestContext textContext = unwrapTextContext(event);
        log.info("before test execution, textContext: {}", textContext);
    }

    @AfterTestExecution
    public void afterTestExecution(TestContextEvent event) {
        TestContext textContext = unwrapTextContext(event);
        log.info("after test execution, textContext: {}", textContext);
    }

    @AfterTestMethod
    public void afterTestMethod(TestContextEvent event) {
        TestContext textContext = unwrapTextContext(event);
        log.info("after test method, textContext: {}", textContext);
    }

    @AfterTestClass
    public void afterTestClass(TestContextEvent event) {
        TestContext textContext = unwrapTextContext(event);
        log.info("after test class, textContext: {}", textContext);
    }

    private TestContext unwrapTextContext(TestContextEvent event) {
        return event.getTestContext();
    }
}
